/*
 * Copyright (C) 2009 Show SMS open source project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bydavy.android.showsms;

//~--- non-JDK imports --------------------------------------------------------

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;

import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;

import android.database.Cursor;

import android.net.Uri;

import android.preference.PreferenceManager;

import android.util.Log;

import com.bydavy.util.showsms.AppLog;

//~--- JDK imports ------------------------------------------------------------

import java.util.HashSet;
import java.util.Set;

/**
 * Inspired by com.android.mms.transaction.MessagingNotification
 *
 *
 * @version        1.0, 10/02/21
 * @author         Davy L.
 */
public class MessageNotification {
    //~--- static fields ------------------------------------------------------
	private static final String[] SMS_STATUS_PROJECTION = new String[] { "thread_id", "date", "address", "body" };
	
    private static final int COLUMN_DATE                   = 1;
    private static final int COLUMN_SMS_ADDRESS            = 2;
    private static final int COLUMN_SMS_BODY               = 3;
    private static final int COLUMN_THREAD_ID              = 0;
    private static final String LOG_TAG                    = AppLog.LOG_TAG;
    private static final boolean DEBUG                     = true;
    private static final String NEW_INCOMING_SM_CONSTRAINT = "( read" + " = 0)";

    /** Field description */
    public static int NOTIFICATION_ID                   = -1;
    
    /** Field description */
    public static final Uri SMS_CONTENT_URI = Uri.parse("content://sms");
    public static final Uri SMS_INBOX_CONTENT_URI = Uri.withAppendedPath(SMS_CONTENT_URI, "inbox");

    public static final Uri MMS_SMS_CONTENT_URI = Uri.parse("content://mms-sms/");
    public static final Uri THREAD_ID_CONTENT_URI = Uri.withAppendedPath(MMS_SMS_CONTENT_URI, "threadID");

    //~--- constructors -------------------------------------------------------

    /**
     * Constructs ...
     *
     */
    private MessageNotification() {}

    //~--- methods ------------------------------------------------------------

    /**
     *
     * @param c
     */
    public static void updateNewMessageIndicator(Context c) {
        Set<Long> threads            = new HashSet<Long>(4);
        MessageNotificationInfo Info = getSmsNewMessageIndicator(c, threads);

        cancelNotification(c, NOTIFICATION_ID);
        Info.deliver(c, threads);
    }

    /**
     * Method description
     *
     *
     * @param c
     */
    public static void cancelAllNotifications(Context c) {
        NotificationManager nm = (NotificationManager) c.getSystemService(Context.NOTIFICATION_SERVICE);

        nm.cancelAll();
    }

    /**
     * Method description
     *
     *
     * @param c
     * @param idNotif
     */
    private static void cancelNotification(Context c, int idNotif) {
        NotificationManager nm = (NotificationManager) c.getSystemService(Context.NOTIFICATION_SERVICE);

        nm.cancel(idNotif);
    }

    //~--- get methods --------------------------------------------------------

    /**
     * Method description
     *
     *
     * @param context
     * @param threads
     *
     * @return
     */
    private static MessageNotificationInfo getSmsNewMessageIndicator(Context context, Set<Long> threads) {
        MessageNotificationInfo info = null;
        ContentResolver resolver     = context.getContentResolver();
        Cursor cursor                = resolver.query(SMS_INBOX_CONTENT_URI, SMS_STATUS_PROJECTION,
                                           NEW_INCOMING_SM_CONSTRAINT, null, "date" + " desc");

        if (cursor == null) {
            return null;
        }

        try {
            if (!cursor.moveToFirst()) {
                return null;
            }

            String address  = cursor.getString(COLUMN_SMS_ADDRESS);
            String body     = cursor.getString(COLUMN_SMS_BODY);
            long threadId   = cursor.getLong(COLUMN_THREAD_ID);
            long timeMillis = cursor.getLong(COLUMN_DATE);

            info = getNewMessageNotificationInfo(context, threadId, address, body, timeMillis, cursor.getCount());
            threads.add(threadId);

            while (cursor.moveToNext()) {
                threads.add(cursor.getLong(COLUMN_THREAD_ID));
            }

            if (DEBUG) {
                Log.v(LOG_TAG, "MessageNotification: " + cursor.getCount() + " sms unreaded");
                Log.v(LOG_TAG, "MessageNotification: " + threads.size() + " threads unreaded");
            }
        } finally {
            cursor.close();
        }

        return info;
    }

    /**
     * Method description
     *
     *
     * @param context
     * @param threadId
     * @param address
     * @param body
     * @param timeMillis
     * @param count
     *
     * @return
     */
    private static MessageNotificationInfo getNewMessageNotificationInfo(Context context, long threadId,
            String address, String body, long timeMillis, int count) {
        Intent clickIntent = new Intent();

        clickIntent.setAction(Intent.ACTION_VIEW);
        clickIntent.addCategory(Intent.CATEGORY_DEFAULT);
        clickIntent.setData(Uri.withAppendedPath(THREAD_ID_CONTENT_URI, String.valueOf(threadId)));
        clickIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

        CharSequence ticker = "sd";
        String title        = "New message";

        return new MessageNotificationInfo(clickIntent, ticker, timeMillis, title, body, count);
    }

    //~--- methods ------------------------------------------------------------

    /**
     * Method description
     *
     *
     * @param context
     */
    public static void updateNotifications(final Context context) {
        new Thread(new Runnable() {
            public void run() {
                updateNewMessageIndicator(context);
            }
        }).start();
    }

    //~--- inner classes ------------------------------------------------------

    /**
     * Class description
     *
     *
     * @version        1.0, 10/02/22
     * @author         Davy L.
     */
    private static final class MessageNotificationInfo {
        private Intent clickIntent;
        private CharSequence contentText;
        private CharSequence contentTitle;
        private int messageCount;
        private CharSequence ticker;
        private long timeMillis;

        /**
         * Constructs ...
         *
         *
         * @param clickIntent
         * @param ticker
         * @param timeMillis
         * @param contentTitle
         * @param contentText
         * @param messageCount
         */
        public MessageNotificationInfo(Intent clickIntent, CharSequence ticker, long timeMillis,
                                       CharSequence contentTitle, CharSequence contentText, int messageCount) {
            this.clickIntent  = clickIntent;
            this.ticker       = ticker;
            this.timeMillis   = timeMillis;
            this.contentTitle = contentTitle;
            this.contentText  = contentText;
            this.messageCount = messageCount;
        }

        /**
         * Method description
         *
         *
         * @param c
         * @param threads
         */
        public void deliver(Context c, Set<Long> threads) {
            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(c.getApplicationContext());

            // loading notification status from SharedPreferences
            boolean notification_def     = Boolean.valueOf(c.getString(R.preferences.notif_enabled_def));
            boolean notification_enabled = sp.getBoolean(c.getString(R.preferences.notif_enabled_key),
                                               notification_def);

            if (notification_enabled) {
                Notification notification = new Notification(R.drawable.show_sms_icon, ticker, timeMillis);

                notification.number = messageCount;

                if (messageCount > 1) {
                    contentText = messageCount + " messages non lus";
                }

                PendingIntent pendingIntent = PendingIntent.getActivity(c, 0, clickIntent, 0);

                notification.setLatestEventInfo(c, contentTitle, contentText, pendingIntent);

                // loading ringtone from SharedPreferences
                String ringtoneUri = sp.getString(c.getString(R.preferences.notif_sound_key), null);

                if (ringtoneUri != null) {
                    notification.sound = Uri.parse(ringtoneUri);
                } else {
                    Log.e(LOG_TAG, "MsgReceiverService :loadPreferences() -> No ringtone uri specified");
                }

                // loading vibration status from SharedPreferences
                boolean vibrate_def = Boolean.valueOf(c.getString(R.preferences.notif_vibrate_def));
                boolean vibrate     = sp.getBoolean(c.getString(R.preferences.notif_vibrate_key), vibrate_def);

                if (vibrate) {
                    notification.defaults |= Notification.DEFAULT_VIBRATE;
                }

                // Flashing light
                notification.defaults |= Notification.DEFAULT_LIGHTS;

                NotificationManager nm = (NotificationManager) c.getSystemService(Context.NOTIFICATION_SERVICE);

                nm.notify(NOTIFICATION_ID, notification);

                if (DEBUG) {
                    Log.v(LOG_TAG, "MessageNotification: new notification submited");
                }
            }
        }
    }
}
